/**
 * Class Monitor
 * To synchronize dining philosophers.
 *
 * @author Serguei A. Mokhov, mokhov@cs.concordia.ca 
 */

public class Monitor
{
	/*
	 * ------------
	 * Data members
	 * ------------
	 */
	
	int numChopSticks;
	static int numChopSticksRemaining;
	boolean canPickUp = true;
	boolean canTalk = true;

	/**
	 * Constructor
	 */
	
	public Monitor(int piNumberOfPhilosophers)
	{	
		System.out.println("Monitor.Monitor");
		// TODO: set appropriate number of chopsticks based on the # of philosophers
		numChopSticks = piNumberOfPhilosophers;
		numChopSticksRemaining = piNumberOfPhilosophers;
	}

	/*
	 * -------------------------------
	 * User-defined monitor procedures
	 * -------------------------------
	 */

	/**
	 * Grants request (returns) to eat when both chopsticks/forks are available.
	 * Else forces the philosopher to wait()
	 */
	public synchronized void pickUp(final int piTID)
	{
		System.out.println("Monitor.pickUp");
		numChopSticksRemaining -=1;
		
		if(numChopSticksRemaining < 2)
		{
			canPickUp = false;
		}
	}

	/**
	 * When a given philosopher's done eating, they put the chopstiks/forks down
	 * and let others know they are available.
	 */
	public synchronized void putDown(final int piTID)
	{
		System.out.println("Monitor.putDown");
		numChopSticksRemaining +=1;
		
		if (numChopSticksRemaining >2)
		{
			canPickUp = true;
		}
	}

	/**
	 * Only one philopher at a time is allowed to philosophy
	 * (while she is not eating).
	 */
	public synchronized void requestTalk()
	{
		System.out.println("Monitor.requestTalk");
		if(canTalk)
		{
			canTalk = false;
		}
		else
		{
			while(!canTalk)
			{
				this.requestTalk();
			}
		}
	}

	/**
	 * When one philosopher is done talking stuff, others
	 * can feel free to start talking.
	 */
	public synchronized void endTalk()
	{
		System.out.println("Monitor.endTalk");
		canTalk = true;
	}
}

// EOF
